How does this apply to BizTalk Server solutions?
BizTalk
Server is the most vendor-neutral product that Microsoft has ever
manufactured. Its 25+ built-in adapters allow it to readily access an
impressive set of industry-standard and vendor-specific technologies.
The question is, how do we make BizTalk Server's external interface as
interoperable as possible in order to support the widest range of
client types? Let's evaluate BizTalk's interoperability support in the
four areas outlined previously.
Deciding
upon an on-ramp technology for the service bus is a critical task. Do
we expose a FILE-based interface that supports legacy applications? How
about a very simple HTTP interface that is sure to please basic web
service clients? Each choice has tradeoffs. Fortunately for BizTalk
architects, this needn't be such a gut-wrenching decision. BizTalk
Server walls off the interface from the implementation logic in a very
loosely-coupled fashion making it possible to support a mix of inbound
channel technologies. Remember that the logical ports in an
orchestration are not associated with a specific technology during
design time. Also recall that even when an orchestration is bound to a
physical messaging artifact at runtime, it is not bound to an individual receive location, but rather to the more encompassing receive port.
A single receive port can contain countless receive locations which all
accept data via different channels. As a result, we should carefully
consider our service audience, and based on that assessment, configure
the acceptable number of endpoints that accommodate our primary
consumers. If we plan on building a very accessible service which also
provides advanced capabilities for modern users, then a receive port
filled with receive locations for both WCF-BasicHttp and WCF-WSHttp
adapters makes sense. This way, our simple clients can still access the
service using classic SOAP capabilities, while our forward-thinking
clients can engage in a more feature-rich service conversation with us.
If we later discover that we have service consumers who cannot speak
HTTP at all, then BizTalk Server still affords us the opportunity to
reveal more traditional endpoints such as FILE or FTP.
One
place that interoperability between systems can subtly fail is when the
data itself is transferred between endpoints. How one platform
serializes a particular data type may be fundamentally different on an
alternate platform. For instance, be sure that if you've defined a
field as nullable that a standard mix of consumers can indeed accept a null value in that data type. Note that the float and decimal
data type may have different levels of precision based on the platform
so you could encounter unexpected rounding of numerical values. Also
consider the handling of datetime values across environments. While the XSD datetime
data type is quite rigid in format, you may choose to use an alternate
date format embedded in a string data type instead. If you do so, you
must ensure that your target service consumers know how to handle a datetime
in that format. In general, a reliance on simpler data types is going
to go a long way towards support for the widest variety of platforms.
You can stay focused on this concept by building your XSD schema first
(and complying with known types) prior to building a service that
adheres to the types in the schema. Fortunately for us BizTalk
developers, we're used to building the contract first.
Alongside
the data structure itself, a service is more interoperable when the
service contract is not needlessly complicated. A complicated WSDL
definition would describe an XSD contract that possessed numerous
nested, imported schemas with a distinct set of namespaces. You may
find that some SOAP toolkits do not properly read WSDL files with these
types of characteristics. While it can initially be seen as a huge
timesaver that application platforms will auto-magically generate a
WSDL from a service, you are often better off creating your own WSDL
file that simplifies the portrayal of the service. Fortunately for us,
both WCF and BizTalk Server support the usage of externally defined
WSDL files as replacements for framework-generated ones.
Service
security is a tricky concept due to the fact that support for
cross-platform security technology has yet to extend into all major
software platforms. WCF (and thus BizTalk Server) exploits the
WS-Security set of standards, which offer platform-neutral security
schemes, but, few vendors have offerings that fully support this
standard. So, when architecting service security, you can either
implement modern security schemes supported through WS-I standards, or,
go the more traditional route of securing the transmission channel with
Secure Sockets Layer (SSL) and/or securing the data throughout its
journey by applying X.509 certificates and encrypting the payload.
The embrace of the service transaction standard is also slow in coming. WCF incorporates the WS-AtomicTransaction and WS-ReliableMessaging standards, but note that BizTalk Server only explicitly supports WS-AtomicTransaction. Be aware that you can make a BizTalk WCF adapter use WS-ReliableMessaging
by manually constructing the binding in the WCF-Custom adapter. Also,
BizTalk's support for service transactions only extends to the point of
publication to the MessageBox, and the distribution of messages from
the MessageBox.
To
design a BizTalk service to be interoperable, with both security and
transaction concepts in mind, you may be forced to implement the
security specifications available by the WS-I organization and educate
service clients as to the types of frameworks and libraries they need
to properly engage these advanced service capabilities.
Reusable
In my humble opinion, the principle of reusability is the most important aspect of a service-oriented architecture. I consider reusability to be a design time objective while reuse
is an inadequate runtime success metric. In essence, reusability is all
about effectively segmenting functionality into services which are
capable of being used by others outside the scope of your immediate
effort. Note the word capable
in the previous sentence. Unless you can predict the future, it's hard
to guarantee that a service module built today will satisfy all the
future needs for similar capabilities. Even if no additional consumers
decide that a service is of use to them, this doesn't
mean
that the service is a failure. By itself, the forethought and decisions
made to make a service reusable makes the construction of the service a
worthwhile effort.
Why does reusability matter? The answers may seem obvious, but I'll call out three explicit benefits:
Future
applications can harvest the functionality of the original service and
accelerate their solution development while encouraging the adoption of
composite applications. Some SOA advocates foresee a world where many
applications consist of very little original functionality but rather,
are simply aggregations of existing services exposed in the enterprise.
A
heavily reused service affords an organization the opportunity to make
solitary changes that cascade to all consumers of that functionality.
Let's say we have a service, which aggregates data from multiple
underlying systems and returns a single, unified view of a customer
entity. Assuming that most major applications in our enterprise use
this service to get information about our customers, we can change the
implementation (swap out data sources, add new sources, change logic)
of this service and each consumer instantly gets the benefits.
The
architectural choices made in designing a reusable service will
inevitably encourage the implementation of the other mentioned SOA
principles such as loose-coupling, abstraction, and interoperability in
addition to other core principles such as composability, encapsulation,
and discoverability.
A
reusable service can be of many diverse shapes and sizes. First of all,
such a service could exhibit a coarse-grained interface that employs a
static contract while supplying a distinct business function. For
instance, a service with an operation named PublishAdverseEvent
(which takes reports of patients experiencing negative effects from a
medication) can be used by every system or business process that might
produce this sort of data. This service takes a very specific payload,
but it can be reused by the multiple systems that encounter this
category of input data. Conversely, we might define a utilitarian
service that archives information to a database through a loose
contract that accepts any structured data as a parameter. This service
also offers a reusable interface that can be applied to a varied set of
use cases. Reusable services may have very generic logic or very
specific logic, flexible contracts or rigid ones, and may be
business-oriented or cross-cutting functional services. A key aspect of
reuse is to define the service in such a way that it can be useful to
those outside of your immediate project scope.
Completely non-technical reusability example
An
intelligent restaurant owner doesn't hire a chef who is only capable of
preparing grilled cheese sandwiches. Instead, they seek out chefs who
are adept at not only repeatedly assembling the same meal, but also
skilled at delivering a wide variety of different meals. The service
offered by the chef, "preparing food", is a reusable service that
accepts multiple inputs and produces an output based on the request
made.
How does this apply to BizTalk Server solutions?
Virtually
every component that comprises a BizTalk solution can be constructed in
a reusable fashion. Take schemas for example. A single schema may be
aggregated into other schemas, or simply applied to multiple different
projects. For instance, a schema describing a standard Address node might be deemed an enterprise standard. Every subsequent schema that must contain an address can import that standard Address
element. That's an example of an incomplete "part" that can only be
useful as a component of another schema. You may also define an
inclusive schema that depicts a standard enterprise entity such as a Product. Any ensuing project that requires processing on a Product
would reference and reuse this pre-defined schema. Look for
opportunities in your schemas to harvest enterprise entities and
elements that may prove useful to those that follow you. When doing so,
consider establishing and applying a project-neutral namespace that
highlights those artifacts as multipurpose instead of project-specific.
Consider your experience when building BizTalk maps. In the development palette, you get access to 80+ functoids
that provide a repeatable, consistent way to perform small fine-grained
activities. When you encounter a situation where an out-of-the-box
functoid won't suffice, BizTalk permits you to either build your own
custom functoids, or, simply reference an external (reusable) component
that holds the functionality you crave.
While the BizTalk Scripting
functoid does allow you to embed isolated code directly into the map,
the window for doing so is quite small and devoid of familiar code
writing comforts such as Intellisense and debugging. This is a polite
way of telling you that you should only embed simplistic code snippets
in the map directly and leave complex or weighty logic to be written in
externally maintained (and hopefully reusable) assemblies.
What
about BizTalk pipelines and pipeline components? By nature, most
pipeline components are built to serve a universal purpose well beyond
the demands of a single consumer. Surely, you could choose to write an archive
receive pipeline component that acted in a very specific way for a very
specific message, but that would be bad form. Instead, a well-written
archive component would accept any content and use configuration
attributes to decide where to publish the archive log. When designing
custom pipeline components, consider first writing all the code
necessary to perform the desired function, and then scan your project
for hard-coded references to aspects that are project-specific (such as
Xpath statements, file path directives). Take those references and turn
them into configuration properties that can be substituted by other
applications at a later time.
WCF
behaviors are now an asset to be reckoned with in a BizTalk
environment. They serve a similar function to pipeline components in
that they process the raw message as it travels in and out of the
BizTalk bus. Reusable WCF behaviors can be written for message logging,
caching, error handling, authorization, and more. What's more, WCF
behaviors can be shared between BizTalk applications and standalone WCF
services. This means that a well-written enterprise service behavior
does not need to be duplicated just to be used in BizTalk Server.
When
should you use WCF behaviors versus BizTalk pipelines? They can both
perform similar actions on the stream of data passing through BizTalk.
However, BizTalk pipelines offer the advantage of knowing about the
BizTalk message type
and thus have clearly defined ways to deal with batching/de-batching
and possess full control over creating or changing the full BizTalk
message context including promoted properties. That said, the continued
focus by Microsoft on WCF technology, and the ability to share WCF
behaviors between BizTalk applications and standard WCF services means
that where possible, you should strongly consider putting generic data
processing logic into WCF behaviors instead of pipelines.
How
about orchestration? On the surface, it might appear that
orchestrations only serve distinct purposes and are lousy candidates
for reuse. While it's true that many workflow processes are targeted to
specific projects, there are clear ways to enjoy the benefits of reuse
here. To begin with, consider the means by which a message enters the
orchestration. It's very convenient to define a "specify later"
orchestration port on the orchestration that is inevitably bound to a
physical receive port. However, this type of port tightly couples
itself to the receive port and thus reduces its potential for reuse.
Wherever possible, look at the Direct Binding option and move your tight coupling to the MessageBox instead of a specific receive port. With direct
binding,
the orchestration simply subscribes directly on the MessageBox, so any
publisher, whether a receive port or another orchestration, can flow
messages into this orchestration.
We
can also choose to perform orchestration decomposition and seek out
reusable aspects of our orchestration that may serve other functions.
For example, you may decide that every exception encountered across
orchestrations should all be handled in the same fashion. Why build
that same processing logic into each and every orchestration? Instead,
you can define a single orchestration which accepts messages from any
orchestration and logs the pertinent details to an exception log and
optionally sends exception notifications to administrators. Our
communal orchestration might accept any content and merely append the
data blob to a common registry. Otherwise, the orchestration could
accept a pre-defined OrchestrationException
schema which all upstream orchestrations inflate prior to publishing
their exception to the MessageBox. Seek out common processing logic and
universal functionality that can be re-factored into a shared assembly
and used across organizational projects.
Finally,
let's talk about reuse in the BizTalk messaging layer. On the message
receipt side, receive locations are quite multipurpose and compel no
specific data format on the messages they absorb. If I define a FILE
receive location, there is absolutely no reason that such a location
couldn't be used to take in a broad mix of message types. However,
let's be realistic and consider a case where a particular receive port
is bound to a specific orchestration. This orchestration processes adverse events
that have occurred with our medical products. The orchestration expects
a very specific format which fortunately, the initial service consumer
adheres to. Inevitably, the next consumer isn't so accommodating and
can only publish a message shaped differently than what the
orchestration expects. Do we need to start over with a new
orchestration? Absolutely not. Instead, we can reuse the exact same
receive port, and even offer to add a new receive location if the
existing service endpoint is inaccessible to the new client. To support
the incompatible data structure, a new map which converts the client
format to the orchestration format can be added to the receive port. In
this scenario, the orchestration was completely reusable, the receive
port was reused, and optionally, the single receive location may have
been reused.
On
the message transmission side, BizTalk send ports also offer
opportunities for reuse. First off, send port maps allow for a
mismatched collection of messages to funnel through a single endpoint
to a destination system. Let's say I have a solitary send port that
updates a company's social events calendar through a service interface.
Even though party notices come from varied upstream systems, we can
flow all of them through this sole send port by continually affixing
new maps to the send port. We don't need a new send port for each
slightly different message containing the same underlying data, but
rather, can aggressively reuse existing ports by simply reshaping the
message into an acceptable structure. Secondly,
BizTalk allows us to define dynamic ports,
which rely on upstream processes to dictate the adapter and endpoint
address for the port. A single dynamic port might be used by countless
consumers who rely on runtime business logic to determine where to
transmit the data at hand. Instead of creating dozens of static send
ports, which are solely used to relay information (i.e, no mapping), we
can repeatedly reuse a single dynamic send port.